﻿using SmartSpace.Core;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SmartSapce.ServiceLocation;

namespace SmartSpace.Workflow
{
    public partial class WorkflowService : IWorkflowService
    {
        public ServiceResult SaveWorkflow(WorkflowMetadata workflow)
        {
            using (WorkflowDbContext context = new WorkflowDbContext())
            {
                EntityRepository.SaveCodeEntity(workflow, context);
                return new ServiceResult(EntityRepository.Commit(context));
            }
        }

        public ServiceResult SaveActivity(ActivityMetadata activity)
        {
            using (WorkflowDbContext context = new WorkflowDbContext())
            {
                if (activity.IsInitial)
                {
                    if (context.Set<ActivityMetadata>().Where(p => p.WorkflowId == activity.WorkflowId && p.IsInitial).Select(p => p.Id).SingleOrDefault() != default(Guid))
                    {
                        return new ServiceResult(false, "只能设置一个初始活动!");
                    }
                }
                EntityRepository.SaveCodeEntity(activity, context);
                return new ServiceResult(EntityRepository.Commit(context));
            }
        }

        public ServiceResult SaveEvent(EventMetadata @event)
        {
            using (WorkflowDbContext context = new WorkflowDbContext())
            {
                EntityRepository.SaveCodeEntity(@event, context);
                return new ServiceResult(EntityRepository.Commit(context));
            }
        }

        public SingleResult<WorkflowMetadata> GetWorkflow(Guid workflowId)
        {
            using (WorkflowDbContext context = new WorkflowDbContext())
            {
                return new SingleResult<WorkflowMetadata>(context.Set<WorkflowMetadata>().Where(p => p.Id == workflowId).SingleOrDefault());
            }
        }

        public SingleResult<WorkflowMetadata> GetWorkflow(string workflowCode)
        {
            using (WorkflowDbContext context = new WorkflowDbContext())
            {
                return new SingleResult<WorkflowMetadata>(context.Set<WorkflowMetadata>().Where(p => p.Code == workflowCode).SingleOrDefault());
            }
        }

        public SingleResult<ActivityMetadata> GetActivity(Guid activityId)
        {
            using (WorkflowDbContext context = new WorkflowDbContext())
            {
                ActivityMetadata activity = context.Set<ActivityMetadata>().Where(p => p.Id == activityId).SingleOrDefault();
                return new SingleResult<ActivityMetadata>(activity);
            }
        }

        public SingleResult<EventMetadata> GetEvent(Guid eventId)
        {
            using (WorkflowDbContext context = new WorkflowDbContext())
            {
                EventMetadata activity = context.Set<EventMetadata>().Where(p => p.Id == eventId).SingleOrDefault();
                return new SingleResult<EventMetadata>(activity);
            }
        }

        public ListResult<WorkflowMetadata> GetWorkflows()
        {
            using (WorkflowDbContext context = new WorkflowDbContext())
            {
                List<WorkflowMetadata> list = context.Set<WorkflowMetadata>().ToList();
                return new ListResult<WorkflowMetadata>(list);
            }
        }

        public ListResult<ActivityMetadata> GetActivities(Guid workflowId)
        {
            using (WorkflowDbContext context = new WorkflowDbContext())
            {
                List<ActivityMetadata> list = context.Set<ActivityMetadata>().Where(p=>p.WorkflowId == workflowId).ToList();
                return new ListResult<ActivityMetadata>(list);
            }
        }
        public List<ActivityMetadata> GetActivities(string refModule)
        {
            using (WorkflowDbContext context = new WorkflowDbContext())
            {
                List<ActivityMetadata> list = context.Set<ActivityMetadata>()
                    .Join(context.Set<WorkflowMetadata>().Where(p=>p.RefModule == refModule),
                        left=>left.WorkflowId,
                        right=>right.Id,
                        (left,right)=>left).ToList();
                return list;
            }
        }

        public ListResult<EventMetadata> GetEvents(Guid activityId)
        {
            using (WorkflowDbContext context = new WorkflowDbContext())
            {
                List<EventMetadata> list = context.Set<EventMetadata>().Where(p => p.FromActivityId == activityId).ToList();
                return new ListResult<EventMetadata>(list);
            }
        }

        public SingleResult<InstanceState> CreateInstance(string refModule, Guid refId, string caption, string creator)
        {
            using (WorkflowDbContext context = new WorkflowDbContext())
            {
                WorkflowMetadata workflow = context.Set<WorkflowMetadata>().Where(p => p.RefModule == refModule).SingleOrDefault();

                // 检查该数据是否已经启动了相关流程
                if (context.Set<WorkflowInstance>().Where(p => p.WorkflowId == workflow.Id && p.RefId == refId && p.RefModule == refModule).Select(p => p.Id).SingleOrDefault() != default(Guid))
                {
                    return new SingleResult<InstanceState>(false, "该数据已经启动了工作流!", null);
                } 
                ActivityMetadata firstActivity = context.Set<ActivityMetadata>().Where(p => p.WorkflowId == workflow.Id && p.IsInitial == true).SingleOrDefault();

                WorkflowInstance instance = new WorkflowInstance();
                instance.Id = Guid.NewGuid();
                instance.WorkflowId = workflow.Id;
                instance.RefId = refId;
                instance.RefModule = refModule;
                instance.Caption = caption;
                instance.CreatedDate = DateTime.Now;
                instance.Creator = creator;
                instance.CurActivityId = firstActivity.Id;
                EntityRepository.Save(instance, context);

                // 创建流程第一步
                WorkflowStep step = new WorkflowStep();
                step.Id = Guid.NewGuid();
                step.WorkflowId = workflow.Id;
                step.ActivityId = firstActivity.Id;
                step.InstanceId = instance.Id;
                step.Sender = creator;
                step.SendedDate = DateTime.Now;
                step.Receiver = creator;
                step.IsActive = true;
                step.IsInitial = true;
                EntityRepository.Save(step, context);

                bool result = EntityRepository.Commit(context);
                if (result)
                {
                    InstanceState state = GetInstanceState(context, refModule, refId);
                    IBizDataUpdater updater = ServiceLocator.GetBizDataUpdater<IBizDataUpdater>(refModule);
                    if (updater != null)
                    {
                        updater.Update(state);
                    }
                }

                return new SingleResult<InstanceState>(GetInstanceState(context, refModule, refId));
            }
        }

        public SingleResult<InstanceState> DriveInstance(Guid instanceId, Guid eventId, Guid refId, string refModule, string @operator, List<string> receivers)
        {
            using (WorkflowDbContext context = new WorkflowDbContext())
            {
                WorkflowStep activeStep = context.Set<WorkflowStep>().Where(p => p.InstanceId == instanceId && p.IsActive && p.Receiver == @operator).SingleOrDefault();
                if (activeStep == null)
                {
                    return new SingleResult<InstanceState>(null);
                }

                WorkflowInstance wfInstance = context.Set<WorkflowInstance>().Where(p => p.Id == instanceId).SingleOrDefault();
                EventMetadata @event = context.Set<EventMetadata>().Where(p => p.Id == eventId).SingleOrDefault();
                ActivityMetadata nextActivity = context.Set<ActivityMetadata>().Where(p => p.Id == @event.ToActivityId).SingleOrDefault();
                List<EventMetadata> nextEvents = context.Set<EventMetadata>().Where(p => p.FromActivityId == nextActivity.Id).ToList();
                // 关闭现有的活动步骤
                activeStep.IsActive = false;
                context.Entry(activeStep).State = System.Data.Entity.EntityState.Modified;

                // 更新流程的最新状态
                wfInstance.CurActivityId = nextActivity.Id;
                context.Entry(wfInstance).State = System.Data.Entity.EntityState.Modified;

                if (nextEvents.Count == 0)
                {
                    // 流程结束
                    // 创建新的活动步骤
                    for (int index = 0; index < receivers.Count; index++)
                    {
                        WorkflowStep step = new WorkflowStep();
                        step.Id = Guid.NewGuid();
                        step.WorkflowId = activeStep.WorkflowId;
                        step.InstanceId = activeStep.InstanceId;
                        step.ActivityId = nextActivity.Id;
                        step.Sender = @operator;
                        step.SendedDate = DateTime.Now;
                        step.Receiver = receivers[index];
                        step.IsActive = false;
                        step.IsFinal = true;
                        context.Set<WorkflowStep>().Add(step);
                    }
                }
                else
                {
                    // 创建新的活动步骤
                    for (int index = 0; index < receivers.Count; index++)
                    {
                        WorkflowStep step = new WorkflowStep();
                        step.Id = Guid.NewGuid();
                        step.WorkflowId = activeStep.WorkflowId;
                        step.InstanceId = activeStep.InstanceId;
                        step.ActivityId = nextActivity.Id;
                        step.Sender = @operator;
                        step.SendedDate = DateTime.Now;
                        step.Receiver = receivers[index];
                        step.IsActive = true;
                        context.Set<WorkflowStep>().Add(step);
                    }
                }

                if (context.SaveChanges() > 0)
                {
                    InstanceState state = GetInstanceState(context, refModule, refId);
                    IBizDataUpdater updater = ServiceLocator.GetBizDataUpdater<IBizDataUpdater>(refModule);
                    if (updater != null)
                    {
                        updater.Update(state);
                    }
                    return new SingleResult<InstanceState>(state);
                }
                return new SingleResult<InstanceState>(null);
            }
        }

        public SingleResult<WorkflowInstance> GetInstance(string refModule, Guid refId)
        {
            using (WorkflowDbContext context = new WorkflowDbContext())
            {
                WorkflowInstance instance = context.Set<WorkflowInstance>().Where(p=>p.RefModule == refModule && p.RefId == refId).SingleOrDefault();
                return new SingleResult<WorkflowInstance>(instance);
            }
        }
        public PagedResult<WorkflowInstance> GetInstances(string module, int start, int limit)
        {
            using (WorkflowDbContext context = new WorkflowDbContext())
            {
                List<WorkflowInstance> instances = context.Set<WorkflowInstance>().Where(p => p.RefModule == module)
                    .OrderBy(p=>p.CreatedDate)
                    .Skip(start)
                    .Take(limit).ToList();
                return new PagedResult<WorkflowInstance>(start, limit, instances.Count, instances);
            }
        }

        public SingleResult<InstanceState> GetInstanceState(string refModule, Guid refId)
        {
            using (WorkflowDbContext context = new WorkflowDbContext())
            {
                return new SingleResult<InstanceState>(GetInstanceState(context, refModule, refId));
            }
        }

        public ListResult<WorkflowTask> GetTasks(string user)
        {
            using (WorkflowDbContext context = new WorkflowDbContext())
            {
                List<WorkflowTask> list = context.Database.SqlQuery<WorkflowTask>(@"select 
wi.Id as instanceid,
wi.WorkflowId,
ws.ActivityId,
wi.RefId,
wi.RefModule,
wi.Caption,
ws.Sender,
ws.SendedDate,
ws.Receiver from wf_instance as wi
	join wf_step as ws on ws.InstanceId = wi.Id
where ws.IsActive=1 and ws.Receiver = {0}", user).ToList();

                return new ListResult<WorkflowTask>(list);
            }
        }

        public ListResult<WorkflowStep> GetActiveSteps(string dataModule, Guid dataId)
        {
            string sql = @"select ws.* from wf_step as ws
join wf_instance as wi on wi.Id = ws.InstanceId
where ws.IsActive = 1 and wi.RefModule={0} and wi.RefId={1}";
            using (WorkflowDbContext context = new WorkflowDbContext())
            {
                List<WorkflowStep> list = context.Database.SqlQuery<WorkflowStep>(sql, dataModule, dataId).ToList();
                return new ListResult<WorkflowStep>(list);
            }
        }
    }
}
